package reesoft.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.MessageConversionException;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;

/**
 * RabbitMQ 公用单元
 *
 * Created by reesoft on 2017-10-12
 */
@Component
public class RabbitMqUtil
{
    private RabbitTemplate rabbitTemplate;

    @Autowired
    public RabbitMqUtil(RabbitTemplate rabbitTemplate)
    {
        this.rabbitTemplate = rabbitTemplate;
        this.rabbitTemplate.setMessageConverter(new JsonMessageConverter());
    }

    /**
     * 创建消息监听器工厂
     *
     * @param MessageType       消息类型
     * @param connectionFactory 连接工厂
     */
    public static SimpleRabbitListenerContainerFactory makeListenerContainerFactory(Class MessageType,
            ConnectionFactory connectionFactory)
    {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new JsonMessageConverter(MessageType));
        return factory;
    }
}

/**
 * JSON 消息转换类
 */
class JsonMessageConverter implements MessageConverter
{
    // 消息类型
    private Class messageType;

    JsonMessageConverter()
    {
        messageType = byte[].class;
    }

    JsonMessageConverter(Class messageType)
    {
        this.messageType = messageType;
    }

    /**
     * 把对象转换为 JSON 字符串消息
     *
     * @param o                 要转换的对象
     * @param messageProperties 消息属性
     * @return 用于发送的 RabbitMQ 消息
     * @throws MessageConversionException
     */
    @Override
    public Message toMessage(Object o, MessageProperties messageProperties) throws MessageConversionException
    {
        //messageProperties.setContentType("application/json"); 这样会导致中文内容被 RabbitMQ 服务器解析出来，以 GB2312 编码方式存储，结果不能以 UTF-8 编码方式解析回 JSON 对象
        messageProperties.setContentType("application/octet-stream");

        try
        {
            return new Message(JSON.toJSONString(o).getBytes("UTF-8"), messageProperties);
        }
        catch (UnsupportedEncodingException e)
        {
            throw new MessageConversionException(e.getMessage());
        }
    }

    /**
     * 把 JSON 字符串消息解析为对象
     *
     * @param message 接收到的 RabbitMQ 消息
     * @return 解析出的对象
     * @throws MessageConversionException
     */
    @Override
    public Object fromMessage(Message message) throws MessageConversionException
    {
        if (messageType == byte[].class)
        {
            return message.getBody();
        }
        else if (messageType == String.class)
        {
            return new String(message.getBody());
        }
        else
        {
            try
            {
                return JSON.parseObject(message.getBody(), messageType);
            }
            catch (JSONException e)
            {
                try
                {
                    return messageType.newInstance();
                }
                catch (IllegalAccessException | InstantiationException e1)
                {
                    e1.printStackTrace();
                    return null;
                }
            }
        }
    }
}
